--[[
  转换gir文件至lua代码
  命令：./lua_scripts/gir2lua.lua ./data/Gtk-2.0.gir ./data/gtk2.args ./lua_scripts/gtk20.lua ./data/gtk20.patch.lua
  需要LUA版本5.3以上，
  luaxml取自：https://github.com/n1tehawk/LuaXML
]]--

function get_gtk_ui_root(ui_data)
    if (ui_data:tag() ~= nil) then  -- and (ui_data:tag() == "interface") then
        return {ui_data, ui_data, 1, nil}
    end
    return nil
end

function get_gtk_ui_first_child(ui_data, node)
    if node ~= nil then
        local curr_node, parent_node, index = node[1], node[2], node[3]
        if curr_node ~= nil then
            local child_table = curr_node:find(nil)
            if child_table ~= nil then
                return {child_table[1], child_table, 1, node}
            end
        end
    end
    return nil
end

function get_gtk_ui_parent(ui_data, node)
    if node ~= nil then
        local parent_node = node[4]
        if parent_node ~= nil then
            return parent_node
        end
    end
    return nil
end

function get_gtk_ui_next_child(ui_data, node, child)
    if node ~= nil then
        local curr_node, parent_node, index = child[1], child[2], child[3]
        if curr_node ~= nil then
            if (parent_node[index + 1] ~= nil) then
                return {parent_node[index + 1], parent_node, index + 1, node}
            end
        end
    end
    return nil
end

function get_gtk_ui_has_child(ui_data, node, name)
    if node ~= nil then
        local curr_node, parent_node, index = node[1], node[2], node[3]
        if curr_node ~= nil then
            for k, v in curr_node:children(name) do
                return true
            end
        end
    end
    return false
end

function get_gtk_ui_get_child(ui_data, node, name)
    if node ~= nil then
        local curr_node, parent_node, index = node[1], node[2], node[3]
        if curr_node ~= nil then
            local child_list = {}
            -- 搜索所有子结点加入到一个临时列表中
            for k, v in curr_node:children(name) do
                table.insert(child_list, v)
            end
            -- 如果列表不为空，则返回第一个子结点
            if child_list[1] ~= nil then
                return {child_list[1], child_list, 1, node}
            end
        end
    end
    return nil
end

function get_gtk_ui_node_name(ui_data, node)
    if node ~= nil then
        if node[1] ~= nil then
            return node[1]:tag()
        end
    end
    return nil
end

function get_gtk_ui_node_value(ui_data, node)
    if node ~= nil then
        if node[1] ~= nil then
            return node[1][1]
        end
    end
    return nil
end

function get_gtk_ui_first_property(ui_data, node)
    if node ~= nil then
        local curr_node, parent_node, index = node[1], node[2], node[3]
        if curr_node ~= nil then
            for key_, val_ in pairs(curr_node) do
                if type(key_) == "string" then  
                    -- print(key_, val_)
                    return {curr_node, {key_, val_}, 1}
                end
            end
            return nil
        end
    end
    return nil
end

function get_gtk_ui_next_property(ui_data, node, attr)
    if attr ~= nil then
        local curr_node, attr_pair, index = attr[1], attr[2], attr[3]
        local next_index = index + 1
        for key_, val_ in pairs(curr_node) do
            if type(key_) == "string" then  
                if index == 0 then
                    -- print(key_, val_)
                    return {curr_node, {key_, val_}, next_index}
                end
                index = index - 1
            end
        end
    end
    return nil
end

function get_gtk_ui_has_property(ui_data, node, name)
    if node ~= nil then
        local curr_node, parent_node, index = node[1], node[2], node[3]
        if curr_node ~= nil then
            for key_, val_ in pairs(curr_node) do
                if (type(key_) == "string") then  
                    if (key_ == name) then
                        return true
                    end
                end
            end
            return false
        end
    end
    return false
end

function get_gtk_ui_get_property(ui_data, node, name)
    if node ~= nil then
        local curr_node, parent_node, index = node[1], node[2], node[3]
        if curr_node ~= nil then
            for key_, val_ in pairs(curr_node) do
                if type(key_) == "string" then  
                    if (key_ == name) then
                        return {curr_node, {key_, val_}, 1}
                    end
                end
            end
            return nil
        end
    end
    return nil
end

function get_gtk_ui_property_name(ui_data, node, attr)
    if attr ~= nil then
        if attr[2] ~= nil then
            return attr[2][1]
        end
    end
    return nil
end

function get_gtk_ui_property_value(ui_data, node, attr)
    if attr ~= nil then
        if attr[2] ~= nil then
            return attr[2][2]
        end
    end
    return nil
end

function get_gtk_ui_property_value_by_name(ui_data, node, name)
    if node ~= nil then
        local curr_node, parent_node, index = node[1], node[2], node[3]
        if curr_node ~= nil then
            if curr_node[name] ~= nil then
                return curr_node[name]
            end
        end
    end
    return nil
end

-- 获取当前脚本的路径
local curr_path = string.match(string.gsub(debug.getinfo(1,"S").short_src, "\\", "/"), "^.*/")
-- 将当前脚本当前目录加入package搜索列表中
package.path = string.format("%s?.lua;%s?/init.lua;%s", curr_path, curr_path, package.path)
print("package.path: " .. package.path)
print("source file: " .. debug.getinfo(1,"S").short_src)

local xml_obj = require("LuaXML")

local gtk_ver = "Gtk224"
local gtk_mod_name = "gtk+-2.0"
local new_prop_format = false;

-- 添加调试 
--require("socket.core")
--require("LuaPanda").start("127.0.0.1", 8818)
print("*****************************************************")

function _check_file_exists(file_name)
    local file_handle = io.open(file_name, "rb")
    if file_handle ~= nil then
        io.close(file_handle) 
        return true
    else
        return false
    end
end

-- get namespace node
function get_namespace_node(gir)
    if type(gir) ~= "table" then
        return nil
    end
    local root_node = get_gtk_ui_root(gir);
    local child_node = get_gtk_ui_first_child(gir, root_node)
    while child_node ~= nil do
        local node_name = get_gtk_ui_node_name(gir, child_node)
        if node_name == "namespace" then
            -- 这里只需要返回namespace节点本身即可
            return child_node
        end
        child_node = get_gtk_ui_next_child(gir, root_node, child_node)
    end
    return nil;
end

function is_key_name(name)
    -- and       break     do        else      elseif end       false     for       function  if
    -- in        local     nil       not       or repeat    return    then      true      until    while
    if name == "and" or name == "break" or name == "do" or name == "else" or
       name == "elseif" or name == "end" or name == "false" or name == "for" or 
       name == "function" or name == "if" or name == "in" or name == "local" or
       name == "nil" or name == "not" or name == "or" or name == "repeat" or 
       name == "return" or name == "then"  or name == "true" or name == "until" or name == "while" then
        return true
    end
    return false
end

-- get any ctype name
function get_ctype_name(ui_data, node)
    -- 一个简短的类型名称映射表，可以从gtkx.0.gir搜索相应枚举、结构、类等得到映射关系
    local gtk_type_to_ctype = {
        ['Gdk.Device'] = "GdkDevice*",
        ['Gdk.DragContext'] = "GdkDragContext*",

        ['Gdk.Event'] = "GdkEvent*",
        ['Gdk.EventAny'] = "GdkEventAny*",
        ['Gdk.EventButton'] = "GdkEventButton*",
        ['Gdk.EventClient'] = "GdkEventClient*",
        ['Gdk.EventCrossing'] = "GdkEventCrossing*",
        ['Gdk.EventConfigure'] = "GdkEventConfigure*",
        ['Gdk.EventExpose'] = "GdkEventExpose*",
        ['Gdk.EventFocus'] = "GdkEventFocus*",
        ['Gdk.EventGrabBroken'] = "GdkEventGrabBroken*", -- gtk3.0
        ['Gdk.EventKey'] = "GdkEventKey*",
        ['Gdk.EventMotion'] = "GdkEventMotion*",
        ['Gdk.EventNoExpose'] = "GdkEventNoExpose*",
        ['Gdk.EventOwnerChange'] = "GdkEventOwnerChange*", -- gtk3.0
        ['Gdk.EventProximity'] = 'GdkEventProximity*',
        ['Gdk.EventProperty'] = "GdkEventProperty*",
        ['Gdk.EventScroll'] = "GdkEventScroll*",
        ['Gdk.EventSelection'] = "GdkEventSelection*",
        ['Gdk.EventSequence'] = "GdkEventSequence*", -- gtk3.0
        ['Gdk.EventWindowState'] = 'GdkEventWindowState*',
        ['Gdk.EventVisibility'] = "GdkEventVisibility*",
        ['Gdk.ModifierType'] = "GdkModifierType*",
        ['Gdk.Rectangle'] = "GdkRectangle*",
        ['Gdk.RGBA'] = "GdkRGBA*", -- gtk3.0
        ['Gdk.Screen'] = "GdkScreen*",

        ['GdkPixbuf.Pixbuf'] = "GdkPixbuf*",   -- 减少一些property搜索args文件
        ['Gio.AppInfo'] = "GAppInfo*", -- gtk3.0
        ['Gio.File'] = "GFile*",  -- gtk3.0
        ['Gio.Volume'] = "GVolume*",  -- gtk3.0
        ['Gio.MountOperation'] = "GMountOperation*", -- gtk3.0
        ['GLib.Error'] = "GError*",  -- gtk3.0
        ['GObject.Object'] = "GObject*",
        ['GObject.Closure'] = "GClosure*",
        ['GObject.ParamSpec'] = "GParamSpec*",

        DragAction = "GdkDragAction*", -- gdk3.0
        CssSection = "GtkCssSection*", -- gtk3.0
        PlacesOpenFlags = "GtkPlacesOpenFlags*", -- gtk3.0
        TextIter = "GtkTextIter*",
        TreeIter = "GtkTreeIter*",
        TreePath = "GtkTreePath*",
        StateFlags = "GtkStateFlags*",
        SelectionData = "GtkSelectionData*",
        Requisition = "GtkRequisition*",
        Allocation = "GtkAllocation*", -- gtk30
    };
    if type(node[1]) ~= "table" then
        return "void"
    end
    -- 判断子结点
    local child_node = get_gtk_ui_first_child(ui_data, node)
    while child_node do
        local type_tag = get_gtk_ui_node_name(ui_data, child_node)
        if type_tag == "type" then
            local c_type = get_gtk_ui_property_value_by_name(ui_data, child_node, "c:type")
            local name_prop = get_gtk_ui_property_value_by_name(ui_data, child_node, "name")
            if c_type ~= nil then
                return c_type;
            elseif name_prop ~= nil then
                -- 特殊处理Gdk.Event这种
                local new_name = name_prop; -- string.gsub(name_prop, "%.", "_")
                if gtk_type_to_ctype[new_name] ~= nil then
                    return gtk_type_to_ctype[new_name]
                else
                    return '{' .. name_prop .. '}'
                end
            end
        elseif type_tag == "array" then
            local c_type = get_gtk_ui_property_value_by_name(ui_data, child_node, "c:type")
            if c_type ~= nil then
                return c_type;
            end
        end
        
        child_node = get_gtk_ui_next_child(ui_data, node, child_node)
    end
    return "void"
end

-- get method parameters
function get_method_params(ui_data, method_node)
    -- get any param name
    local function get_param_name(ui_data, node)
        if type(node[1]) ~= "table" then
            return nil
        end
        local name_prop = get_gtk_ui_property_value_by_name(ui_data, node, "name")
        if name_prop ~= nil then
            return name_prop
        end
        return nil
    end
    local index = 1
    local params = {}
    if type(method_node) ~= "table" then
        return nil
    end

    -- 遍历方法的子节点
    local params_node = get_gtk_ui_first_child(ui_data, method_node)
    while params_node do
        -- 结点名称
        local params_name = get_gtk_ui_node_name(ui_data, params_node)
        if params_name == "parameters" then
            -- 遍历参数结点
            local one_param = get_gtk_ui_first_child(ui_data, params_node)
            while one_param do
                local param_name = get_gtk_ui_node_name(ui_data, one_param)
                if param_name == "instance-parameter" then
                    local tmp_tbl = {}
                    tmp_tbl[1] = get_ctype_name(ui_data, one_param)
                    tmp_tbl[2] = get_param_name(ui_data, one_param)
                    params[index] = tmp_tbl
                    index = index + 1
                elseif param_name == "parameter" then
                    local tmp_tbl = {}
                    tmp_tbl[1] = get_ctype_name(ui_data, one_param)
                    tmp_tbl[2] = get_param_name(ui_data, one_param)
                    params[index] = tmp_tbl
                    index = index + 1
                end
                one_param = get_gtk_ui_next_child(ui_data, params_node, one_param)
            end
            return params
        end

        params_node = get_gtk_ui_next_child(ui_data, method_node, params_node)
    end 
    return nil
end

local gtk_classes = {};
local gtk_interfaces = {};
local gtk_enumerationes = {};
-- local signal_name_max_len = 1
-- local property_name_max_len = 1

function table_length(ori_tbl)
    if (type(ori_tbl) ~= "table") then
        return 0
    end
    local max_index = 0
    -- must use pairs function
    for _, _ in pairs(ori_tbl) do
        max_index = max_index + 1
    end
    return max_index
end

-- 默认函数前缀，后续代码会根据namespace中的信息修改
func_prefix = "gtk"
type_prefix = "Gtk"

-- get one class info
function build_class_info(ui_data, parent_node, args_child_property_list, args_property_list)
    -- get method return type
    local function get_method_ret(ui_data, method_node)
        if type(method_node) ~= "table" then
            return "void"
        end
        -- 遍历方法的子节点
        local child_node = get_gtk_ui_first_child(ui_data, method_node)
        while child_node do
            local node_name = get_gtk_ui_node_name(ui_data, child_node)
            if node_name == "return-value" then
                return get_ctype_name(ui_data, child_node)
            end
            child_node = get_gtk_ui_next_child(ui_data, method_node, child_node)
        end
        return "void"
    end
    -- get method info
    local function get_method_info(ui_data, class_node, method_name)
        if type(class_node) ~= "table" then
            return nil
        end
        local child_node = get_gtk_ui_first_child(ui_data, class_node)
        while child_node do
            local node_name = get_gtk_ui_node_name(ui_data, child_node)
            if node_name == "method" then
                local method_name_2 = get_gtk_ui_property_value_by_name(ui_data, child_node, "name")
                -- check method name property
                if method_name_2 == method_name then
                    local method_info = {}
                    method_info["return"] = get_method_ret(ui_data, child_node)
                    method_info["parameter"] = get_method_params(ui_data, child_node)
                    return method_info
                end
            end
            child_node = get_gtk_ui_next_child(ui_data, class_node, child_node)
        end
        return nil
    end
    local function get_child_property_in_args(child_property_list, typename)
        return child_property_list[typename]
    end

    local function build_virtual_method(ui, child, prop_name)
        local method_info = {}
        if prop_name ~= nil then
            local new_v_method_name = prop_name; -- string.gsub(node_prop_name, "-", "_")
            method_info["return"] = get_method_ret(ui, child)
            method_info["parameter"] = get_method_params(ui, child) -- need patch it
        end
        return method_info
    end
    local function build_method(ui, child, prop_name, class_info_)
        local method_info = {}
        local new_method_name = prop_name; -- string.gsub(node_prop_name, "-", "_")
        local c_identifier = get_gtk_ui_property_value_by_name(ui_data, child, "c:identifier")
        if c_identifier ~= nil then
            method_info["fullname"] = c_identifier
        else
            method_info["fullname"] = class_info_["func_prefix"] .. "_" .. string.gsub(new_method_name, "-", "_")
        end
        method_info["return"] = get_method_ret(ui, child)
        method_info["parameter"] = get_method_params(ui, child) -- need patch it
        return method_info
    end
    local function build_signal(ui, child, prop_name, class_info_, class_name_)
        local new_signal_name = prop_name; -- string.gsub(node_prop_name, "-", "_")
        -- 对应的虚拟函数有可能是带下划线的
        local fake_signal_name = string.gsub(prop_name, "-", "_")

        -- 获取得到相应的函数信息
        local method_info = {}
        -- 重复项时，以virtual-method中为准?
        if ((class_info_["virtual-method"] == nil) or 
            (class_info_["virtual-method"][new_signal_name] == nil) or
            (class_info_["virtual-method"][fake_signal_name] == nil)) then
            method_info["return"] = get_method_ret(ui, child)
            -- 对于glib:signal的参数，是缺少instant-param参数的，需要进行patch
            local signal_params = get_method_params(ui, child)
            local widget_param  = {}
            widget_param[1] = class_info_["typename"] .. "*"
            widget_param[2] = string.lower(class_name_)
            -- 参数为空时
            if signal_params ~= nil then
                table.insert(signal_params, 1, widget_param)
            else
                local new_signal_params = {}
                new_signal_params[1] = widget_param
                signal_params = new_signal_params
            end
            method_info["parameter"] = signal_params
            print("[ERROR] " .. class_info_["typename"] .. " have a signal by glib:signal may not exist virtual-method, [".. prop_name .."]")
        else
            if (class_info_["virtual-method"][new_signal_name] == nil) then
                print("[INFO]" .. class_info_["typename"] .. " have a signal, with same virtual-method(fake), [".. prop_name .."], COPY IT.");
                return class_info_["virtual-method"][fake_signal_name];
            else
                print("[INFO]" .. class_info_["typename"] .. " have a signal, with same virtual-method, [".. prop_name .."], COPY IT.");
                return class_info_["virtual-method"][new_signal_name];
            end
        end
        return method_info;
    end
    local function build_constructor(ui, child, prop_name, class_info_)
        local method_info = {}
        method_info["return"] = get_method_ret(ui, child)
        local c_identifier = get_gtk_ui_property_value_by_name(ui, child, "c:identifier")
        if c_identifier ~= nil then
            method_info["functionname"] = c_identifier
        else
            method_info["functionname"] = class_info_["func_prefix"] .. '_' .. prop_name
        end
        method_info["parameter"] = get_method_params(ui, child)
        return method_info
    end
    local function build_property(ui, child, parent, prop_name, class_info_)
        local function get_item_in_args(args_property_list, class_name, property_name, item_tag)
            if args_property_list == nil then
                return nil
            end
            if args_property_list[class_name] == nil then
                return nil
            end
            local prop_item = args_property_list[class_name][property_name]
            if prop_item == nil then
                return nil
            end
            if prop_item[item_tag] ~= nil then
                return prop_item[item_tag]
            end
            return nil
        end
        local function get_default_string_in_args(args_property_list, class_name, property_name)
            return get_item_in_args(args_property_list, class_name, property_name, "default")
        end
        local function get_type_in_args(args_property_list, class_name, property_name)
            return get_item_in_args(args_property_list, class_name, property_name, "type")
        end
        local function get_flags_in_args(args_property_list, class_name, property_name)
            return get_item_in_args(args_property_list, class_name, property_name, "flags")
        end
        --local property_name = prop_name; --string.gsub(node_prop_name, "-", "_")
        -- get type, default value, write function name
        local set_method_name = "set_" .. string.gsub(prop_name, "-", "_")
        local set_from_method_name = "set_from_" .. string.gsub(prop_name, "-", "_")
        local property_info = {}
        -- property ctype name
        property_info["type"] = get_ctype_name(ui, child)
        -- 如果属性的类型不正确，尝试到args去查找
        if string.sub(property_info["type"], 1, 1) == "{" or property_info["type"] == "void" then
            local new_type_name = get_type_in_args(args_property_list, class_info_["typename"], prop_name)
            if new_type_name ~= nil then
                property_info["type"] = new_type_name
            end
        end
        -- property origin name
        property_info["origin"] = prop_name;
        -- property default value.
        local default_string = get_default_string_in_args(args_property_list, class_info_["typename"], prop_name)
        if default_string ~= nil then
            -- 如果是字符串，则需要将"替换成\"
            property_info["default"] = string.gsub(default_string, "\"", "\\\"") -- default_string;
        end
        -- 如果是构造对象，设置一个标志
        if get_gtk_ui_property_value_by_name(ui, child, "construct") == "1" then
            property_info["construct"] = 1;
        end
        -- 找到不到对应的set函数，则不生成functionname与setfunction属性
        local set_propery_func_info = get_method_info(ui, parent, set_method_name)
        if set_propery_func_info == nil then
            local set_from_propery_func_info = get_method_info(ui, parent, set_from_method_name)
            if set_from_propery_func_info ~= nil then
                print("[WARN] ".. class_info_["name"] .. "missing set :" .. set_method_name .. ", but exist " .. set_from_method_name)
                set_propery_func_info = set_from_propery_func_info
                set_method_name = set_from_method_name
            end
        end
        if set_propery_func_info ~= nil then
            property_info["functionname"] = class_info_["func_prefix"] .. '_' .. set_method_name;
            -- set property method info.
            property_info["setfunction"] = set_propery_func_info;
            -- if string.len(get_gtk_ui_property_value_by_name(ui, child, "name")) > property_name_max_len then
            --  property_name_max_len = string.len(get_gtk_ui_property_value_by_name(ui, child, "name")) + 1
            --end
            -- 如果没有ctype类型时，有setfunction, 从setfunction的第二个参数类型中取得
            if string.sub(property_info["type"], 1, 1) == "{" then
                if set_propery_func_info["parameter"] ~= nil and 
                    set_propery_func_info["parameter"][2] ~= nil and 
                    set_propery_func_info["parameter"][2][1] ~= nil then
                    property_info["type"] = set_propery_func_info["parameter"][2][1]
                end
            end
        else
            property_info["missing_set"] = 1;
            if get_gtk_ui_property_value_by_name(ui, child, "writable") ~= "1" then
                property_info["rwflags"] = "r";
            end
        end
        -- 再根据flags，填充是否为只读或读写
        local flags = get_flags_in_args(args_property_list, class_info_["typename"], prop_name)
        if property_info["rwflags"] ~= nil and flags ~= property_info["rwflags"] then
            print("[ERROR] bad rwflags in " .. prop_name)
        end
        property_info["rwflags"] = flags;
        return property_info
    end

    local class_info = {}
    if type(parent_node[1]) ~= "table" then
        return nil, ""
    end
    -- must exist name
    local class_name = get_gtk_ui_property_value_by_name(ui_data, parent_node, "name")
    if class_name == nil then
        return nil, ""
    end
    --if class_name == "PrintOperationPreview" then
        -- 中断，然后点VSCODE的中断暂停调试，然后再输入cont，即可单步执行
        --debug.debug();
    --end
    
    print("[INFO] start class:" .. class_name)
    class_info["name"] = class_name;

    -- c:type
    local c_type = get_gtk_ui_property_value_by_name(ui_data, parent_node, "c:type")
    if c_type == nil then
        print(class_info["name"] .. " missing c:type for " .. class_name)
        class_info["typename"] = type_prefix .. class_name;
    else
        class_info["typename"] = c_type;
    end
    local parent_name = get_gtk_ui_property_value_by_name(ui_data, parent_node, "parent")
    if parent_name ~= nil then
        class_info["parent"] = parent_name;
    end
    -- function prefix, example: gtk_ + about_dialog
    local symbol_prefix = get_gtk_ui_property_value_by_name(ui_data, parent_node, "c:symbol-prefix")
    if symbol_prefix == nil then
        print(class_info["name"] .. " missing c:symbol-prefix")
        class_info["func_prefix"] = func_prefix .. string.gsub(class_name, "%u", function (s) return "_" .. string.lower(s) end)
    else
        class_info["func_prefix"] = func_prefix .."_" .. symbol_prefix
    end
    
    -- gtk_about_dialog ==> GTK_ABOUT_DIALOG, use for gen: gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG([!WIDGETID]), (gchar*)[!PROPERTY_VALUE]);
    -- local macro_name = string.upper(class_info["func_prefix"])
    
    -- all constructor/signal/property
    class_info["constructor"] = {}
    class_info["signal"] = {}
    class_info["property"] = {}
    class_info["method"] = {}
    class_info["implement"] = {}
    class_info["virtual-method"] = {}

    local child_node = get_gtk_ui_first_child(ui_data, parent_node)
    while child_node ~= nil do
        local node_tag = get_gtk_ui_node_name(ui_data, child_node)
        local node_prop_name = get_gtk_ui_property_value_by_name(ui_data, child_node, "name")
        -- 信号可能存在重复项
        if node_tag == "virtual-method" then
            -- start signal
            if node_prop_name ~= nil then -- string.gsub(node_prop_name, "-", "_")
                if class_info["virtual-method"][node_prop_name] ~= nil then
                    print("[ERROR]  dup virtual-method " .. node_prop_name)
                end
                class_info["virtual-method"][node_prop_name] = build_virtual_method(ui_data, child_node, node_prop_name)
            else
                print("class: " .. class_info["name"] .. "have one unnamed signal!")
            end
        elseif node_tag == "function" or node_tag == "method" then
            -- start method
            if node_prop_name ~= nil then
                class_info["method"][node_prop_name] = build_method(ui_data, child_node, node_prop_name, class_info)
            else
                print("class: " .. class_info["name"] .. "have one unnamed method!")
            end
        elseif node_tag == "glib:signal" then
            -- start signal
            if node_prop_name ~= nil then
                class_info["signal"][node_prop_name] = build_signal(ui_data, child_node, node_prop_name, class_info, class_name)
            else
                print("class: " .. class_info["name"] .. "have one unnamed signal!");
            end
        elseif node_tag == "constructor" then
            -- start constructor
            if node_prop_name ~= nil then
                class_info["constructor"][node_prop_name] = build_constructor(ui_data, child_node, node_prop_name, class_info)
            else
                print("class: " .. class_info["name"] .. "have one unnamed constructor!")
            end
        elseif node_tag == "implements" then
            -- start implements
            if node_prop_name ~= nil then
                class_info["implement"][#class_info["implement"] + 1] = node_prop_name
            else
                print("class: " .. class_info["name"] .. "have one unnamed implements!")
            end
        elseif node_tag == "property" then
            -- start property
            if node_prop_name ~= nil then
                class_info["property"][node_prop_name] = build_property(ui_data, child_node, parent_node, node_prop_name, class_info)
            else
                print("class: " .. class_info["name"] .. "have one unnamed property!")
            end
        end

        child_node = get_gtk_ui_next_child(ui_data, parent_node, child_node)
    end

    local child_property = get_child_property_in_args(args_child_property_list, class_info["typename"])
    if child_property ~= nil then
        class_info["child_property"] = child_property
    end

    return class_info, class_info["name"]
end

function class_has_this_property(class_node, property_name)
    local tmp_class_node = class_node
    if tmp_class_node["property"] ~= nil then
        local property_tbl = tmp_class_node["property"]
        repeat
            for name, _ in pairs(property_tbl) do
                if property_name == name then
                    return true, false
                -- 如果属性名称中，将下划线变更为-，也存在，此时也返回true
                elseif string.gsub(property_name, "_", "-") == name then
                    return true, true
                end
            end
            -- 判空
            if tmp_class_node == nil or tmp_class_node["parent"] == nil or gtk_classes[tmp_class_node["parent"]] == nil then
                break
            end
            tmp_class_node = gtk_classes[tmp_class_node["parent"]]
            property_tbl = tmp_class_node["property"]
        until property_tbl == nil
    end
    -- 判断实现的接口中是否该属性
    if class_node["implement"] ~= nil then
        for _, name in ipairs(class_node["implement"]) do
            if gtk_interfaces[name] ~=nil then
                local has_hit, is_down = class_has_this_property(gtk_interfaces[name], property_name)
                if has_hit then
                    return has_hit, is_down
                end
            end
        end
    end
    return false, false
end

function write_gtk_class_code(class_node, dest_handle)
    local function cvt_param_list_for_constructor(class_node, params)
        if params == nil then
            return ''
        end
        local params_type = ''
        for _, v in ipairs(params) do
            if params_type == "" then
                if new_prop_format then
                    local has_hit, is_down = class_has_this_property(class_node, v[2]);
                    if has_hit and is_down then
                        params_type = params_type .. '(' .. v[1] .. ')({* this[\'' .. string.gsub(v[2], "_", "-") .. '\']value *})'
                    else
                        params_type = params_type .. '(' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                    end
                else
                    params_type = params_type .. '(' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                end
            else
                -- 对于不定参数，需要特殊处理
                if v[2] == "..." then
                    params_type = params_type .. ', 0'
                else
                    -- 匹配一下这个属性，以更好地
                    local has_hit, is_down = class_has_this_property(class_node, v[2]);
                    if has_hit then
                        if new_prop_format and is_down then
                            local new_name = string.gsub(v[2], "_", "-");
                            params_type = params_type .. ', (' .. v[1] .. ')({* this[\'' .. new_name .. '\'].value *})'
                        else
                            params_type = params_type .. ', (' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                        end
                    else
                        params_type = params_type .. ', (' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                    end
                end
            end
        end
        return params_type
    end
    local function cvt_param_list_for_constructor_param(class_node, params)
        if params == nil then
            return {}, {}
        end
        local params_type = {}
        local params_name = {}
        -- 提取非属性的参数类型、参数名称
        for _, v in ipairs(params) do
            local has_hit, is_down = class_has_this_property(class_node, v[2]);
            if has_hit then
                -- 跳过void类型
                if v[1] ~= "void" then
                    table.insert(params_type, v[1])
                    -- 如果是下划线变换成-匹配的
                    if new_prop_format and is_down then
                        local new_name = string.gsub(v[2], "_", "-");
                        table.insert(params_name, new_name)
                    else
                        table.insert(params_name, v[2])
                    end
                end
            else
                print("[ERROR] " .. class_node["name"] .. " don't have this property: [" .. v[2] .. "]")
            end
        end
        return params_type, params_name
    end
    local function write_constructor_code(class_node, dest_handle)
        -- write xxx_constructor
        dest_handle:write("  constructor = { \n");
        dest_handle:write("    -- 名称[- ==> _], \n");
        local name_max_len = 1
    
        -- 用于排序构建器名称
        local sort_name = {}
        -- 查找当前构建器列表的名字最长长度
        for name, _ in pairs(class_node["constructor"]) do
            local name_len = string.len(name)
            if name_len > name_max_len then
                name_max_len = name_len
            end
            table.insert(sort_name, 1, name)
        end
        -- 排序一下构建器名称
        table.sort(sort_name)
    
        -- 信号以字母顺序输出
        for _, name in ipairs(sort_name) do
            local cur_name_len = string.len(name)
            local full_lua_line = "    " .. name
            -- 补齐空格，对齐文字
            if cur_name_len < name_max_len then
                full_lua_line = full_lua_line .. string.rep(" ", name_max_len - cur_name_len)
            end
    
            local constructor_str = cvt_param_list_for_constructor(class_node, class_node["constructor"][name]["parameter"]);
            -- 构建函数体
            full_lua_line = full_lua_line ..' = { gencode = "' .. class_node["constructor"][name]["functionname"] .. '(' .. constructor_str .. ')", \n'
            -- 整个构建参数信息
            local params_type, params_name = cvt_param_list_for_constructor_param(class_node, class_node["constructor"][name]["parameter"])
            if table_length(params_type) > 0 then
                full_lua_line = full_lua_line ..'            params = { type = {"' .. table.concat(params_type, '", "')  .. '"}, \n' 
                full_lua_line = full_lua_line ..'                       name = {"' .. table.concat(params_name, '", "')  .. '"} } },\n'
            else
                full_lua_line = full_lua_line ..'            params = { type = {}, name = {} } },\n'
            end
    
            dest_handle:write(full_lua_line);
        end
    
        dest_handle:write("  },\n");
    end
    local function cvt_param_list_for_new_method(class_node, params)
        if params == nil then
            return ''
        end
        local params_type = ''
        for _, v in ipairs(params) do
            if params_type == "" then
                params_type = params_type .. '(' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
            else
                -- 检测v[2]在不在property列表中，不在，则
                local has_hit, is_down = class_has_this_property(class_node, v[2])
                if has_hit then
                    if new_prop_format and is_down then
                        local new_name = string.gsub(v[2], "_", "-");
                        params_type = params_type .. ', (' .. v[1] .. ')({* this.[\'' .. new_name .. '\'].value *})'
                    else
                        params_type = params_type .. ', (' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                    end
                else
                    -- 对于不定参数，需要特殊处理
                    if v[2] == "..." then
                        params_type = params_type .. ', 0'
                    else
                        print("[ERROR] " .. class_node["name"] .. " don't have this property: [" .. v[2] .. "]")
                        params_type = params_type .. ', (' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                    end
                end
            end
        end
        return params_type
    end
    local function cvt_param_list_for_new_method_param(class_node, params)
        if params == nil then
            return {}, {}
        end
        local params_type = {}
        local params_name = {}
        -- 提取非属性的参数类型、参数名称
        for _, v in ipairs(params) do
            if v[1] ~= "void" then
                -- 跳过void类型
                table.insert(params_type, v[1])
                table.insert(params_name, v[2])
            end
        end
        return params_type, params_name
    end
    local function cvt_param_list_for_method(class_node, params)
        if params == nil then
            return ''
        end
        local params_type = ''
        for k, v in ipairs(params) do
            if k == 1 then
                params_type = '(' .. v[1] .. ')({* id *})'
            elseif params_type == "" then
                params_type = params_type .. '(' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
            else
                -- 检测v[2]在不在property列表中，不在，则
                local has_hit, is_down = class_has_this_property(class_node, v[2])
                if has_hit then
                    if new_prop_format and is_down then
                        local new_name = string.gsub(v[2], "_", "-");
                        params_type = params_type .. ', (' .. v[1] .. ')({* this.[\'' .. new_name .. '\'].value *})'
                    else
                        params_type = params_type .. ', (' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                    end
                else
                    -- 对于不定参数，需要特殊处理
                    if v[2] == "..." then
                        params_type = params_type .. ', 0'
                    else
                        params_type = params_type .. ', (' .. v[1] .. ')({* this.' .. v[2] .. '.value *})'
                    end
                end
            end
        end
        return params_type
    end
    local function cvt_param_list_for_method_param(class_node, params)
        if params == nil then
            return {}, {}
        end
        local params_type = {}
        local params_name = {}
        -- 提取非属性的参数类型、参数名称
        for k, v in ipairs(params) do
            if k ~= 1 and v[1] ~= "void" then
                -- 跳过void类型
                table.insert(params_type, v[1])
                table.insert(params_name, v[2])
            end
        end
        return params_type, params_name
    end
    local function write_method_code(class_node, dest_handle)
        dest_handle:write("  method = { \n");
        dest_handle:write("    -- 函数名称  完整名字  返回值  函数参数\n");
    
        if class_node["method"] ~= nil and type(class_node["method"]) == "table" then
            local default_max_len = 0
            local full_name_max_len = 1
            local method_name_max_len = 1
    
            -- 用于排序属性名称
            local sort_name = {}
            -- 查找当前属性列表的类型最长长度
            for name, detail in pairs(class_node["method"]) do
                local full_name_len = string.len(detail["fullname"])
                if full_name_len > full_name_max_len then
                    full_name_max_len = full_name_len
                end
                local method_name_len = string.len(name)
                if method_name_len > method_name_max_len then
                    method_name_max_len = method_name_len
                end
                table.insert(sort_name, 1, name)
            end
            -- 排序一下信号名称
            table.sort(sort_name)
    
            -- 信号以字母顺序输出
            for _, name in ipairs(sort_name) do
            --for k, v in pairs(class_node["property"]) do
                local method_name_len = string.len(name)
                local full_lua_line = "    " .. name
                -- 函数完整名字，补齐空格，对齐文字
                if method_name_len < method_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", method_name_max_len - method_name_len)
                end
                full_lua_line = full_lua_line  .. ' = { fullname ="' .. class_node["method"][name]["fullname"] .. '", '
    
                -- 函数返回值类型
                full_lua_line = full_lua_line  .. 'ret ="' .. class_node["method"][name]["return"] .. '", \n'
    
                -- 函数完整信息
                local method_str = cvt_param_list_for_method(class_node, class_node["method"][name]["parameter"]);
                -- 构建函数体
                full_lua_line = full_lua_line  .. string.rep(" ", method_name_max_len + 9) .. 'gencode = "' .. class_node["method"][name]["fullname"] .. '(' .. method_str .. ')", \n'
                -- 整个构建参数信息
                local params_type, params_name = cvt_param_list_for_method_param(class_node, class_node["method"][name]["parameter"])
                if table_length(params_type) > 0 then
                    full_lua_line = full_lua_line  .. string.rep(" ", method_name_max_len + 5) .. '    params = { type = {"' .. table.concat(params_type, '", "')  .. '"}, \n' 
                    full_lua_line = full_lua_line  .. string.rep(" ", method_name_max_len + 5) .. '               name = {"' .. table.concat(params_name, '", "')  .. '"} } },\n'
                else
                    full_lua_line = full_lua_line  .. string.rep(" ", method_name_max_len + 5) .. '    params = { type = {}, name = {} } },\n'
                end
    
                dest_handle:write(full_lua_line);
            end
        end
        dest_handle:write("  },\n");
    end
    local function cvt_param_type_for_signal(params)
        if params == nil then
            return ''
        end
        local params_type = ""
        for _, v in ipairs(params) do
            if params_type == "" then
                params_type = params_type .. '"' .. v[1] .. '"'
            else
                params_type = params_type .. ', "' .. v[1] .. '"'
            end
        end
        return params_type
    end
    local function cvt_param_body_for_signal(params)
        if params == nil then
            return ''
        end
        local params_body = ""
        for _, v in ipairs(params) do
            if params_body == "" then
                params_body = params_body .. '"' .. v[2] .. '"'
            else
                params_body = params_body .. ', "' .. v[2] .. '"'
            end
        end
        return params_body
    end
    local function write_signal_code(class_node, dest_handle)
        dest_handle:write("  signal = { \n");
        dest_handle:write("    -- 信号名称[- ==> _], 信号返回值, 信号参数列表\n");
    
        if class_node["signal"] ~= nil and type(class_node["signal"]) == "table" then
            local return_name_max_len = 1
            local signal_name_max_len = 1
    
            -- 用于排序信号名称
            local sort_name = {}
            -- 查找当前属性列表的类型最长长度
            for name, detail in pairs(class_node["signal"]) do
                local return_name_len = string.len(detail["return"])
                if return_name_len > return_name_max_len then
                    return_name_max_len = return_name_len
                end
                local signal_name_len = string.len(name)
                -- 如果信号名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    signal_name_len = signal_name_len + 4
                -- 如果信号名称中包含'-'，则加上4个字符
                elseif string.find(name, '-') then
                    signal_name_len = signal_name_len + 4
                end
                if signal_name_len > signal_name_max_len then
                    signal_name_max_len = signal_name_len
                end
                table.insert(sort_name, 1, name)
            end
            -- 排序一下信号名称
            table.sort(sort_name)
    
            -- 信号以字母顺序输出
            for _, name in ipairs(sort_name) do
                local signal_name_len = string.len(name)
                local full_lua_line = "    " .. name
                -- 如果信号名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    full_lua_line = "    ['" .. name .. "']"
                    signal_name_len = signal_name_len + 4
                -- 如果信号名称中包含'-'，则加上4个字符
                elseif string.find(name, '-') then
                    full_lua_line = "    ['" .. name .. "']"
                    signal_name_len = signal_name_len + 4
                end
                -- 补齐空格，对齐文字
                if signal_name_len < signal_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", signal_name_max_len - signal_name_len)
                end
    
                full_lua_line = full_lua_line ..' = {ret_type = "' .. class_node["signal"][name]["return"] .. '"'
    
                local return_name_len = string.len(class_node["signal"][name]["return"])
                -- 补齐空格，对齐文字
                if return_name_len < return_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", return_name_max_len - return_name_len)
                end
                full_lua_line = full_lua_line .. ', params = {type = {' .. cvt_param_type_for_signal(class_node["signal"][name]["parameter"])
                full_lua_line = full_lua_line .. '}, name ={' .. cvt_param_body_for_signal(class_node["signal"][name]["parameter"]) .. "}} }, \n"
                dest_handle:write(full_lua_line);
            end
        end
    
        dest_handle:write("  },\n");
    end
    local function cvt_param_list_for_property(params, sub_tag)
        if params == nil then
            return ''
        end
        local params_type = ""
        --local index = 1
        if params["parameter"] ~= nil then
            for k, v in ipairs(params["parameter"]) do
                if k == 1 then
                    params_type = '(' .. v[1] .. ')({* id *})'
                else
                    -- 属性对应的执行函数，目前都是只有一个属性值
                    params_type = params_type .. ', (' .. v[1] .. ')({* property.value *})'
                    --params_type = params_type .. ', (' .. v .. ')[!PROPERTY_VALUE<'.. sub_tag .. '>]'
                    -- index = index + 1
                end
            end
        end
        return params_type
    end
    local function write_property_code(class_node, dest_handle)
        dest_handle:write("  property = { \n");
        dest_handle:write("    -- 属性名称  属性类型 缺省值 代码生成\n");
    
        if class_node["property"] ~= nil and type(class_node["property"]) == "table" then
            local type_name_max_len = 1
            local default_max_len = 0
            local property_name_max_len = 1
    
            -- 用于排序属性名称
            local sort_name = {}
            -- 查找当前属性列表的类型最长长度
            for name, detail in pairs(class_node["property"]) do
                local type_name_len = string.len(detail["type"])
                if type_name_len > type_name_max_len then
                    type_name_max_len = type_name_len
                end
                local property_name_len = string.len(name)
                -- 如果属性的名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    property_name_len = property_name_len + 4
                -- 如果属性的名称中包含-
                elseif new_prop_format and string.find(name, "-") ~= nil then
                    property_name_len = property_name_len + 4;
                end
                if property_name_len > property_name_max_len then
                    property_name_max_len = property_name_len
                end
                -- 如果有 default
                if detail["default"] ~= nil then
                    local default_len = string.len(detail["default"])
                    if default_len > default_max_len then
                        default_max_len = default_len
                    end
                end
                table.insert(sort_name, 1, name)
            end
            -- 排序一下信号名称
            table.sort(sort_name)
    
            -- 信号以字母顺序输出
            for _, name in ipairs(sort_name) do
            --for k, v in pairs(class_node["property"]) do
                local property_name_len = string.len(name)
                -- 如果属性的名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    property_name_len = property_name_len + 4
                -- 如果属性的名称中包含-
                elseif new_prop_format and string.find(name, "-") ~= nil then
                    property_name_len = property_name_len + 4;
                end
                local type_name_len = string.len(class_node["property"][name]["type"])
                --  缺省长度为0
                local default_len = 0
                if class_node["property"][name]["default"] ~= nil then
                    default_len = string.len(class_node["property"][name]["default"] )
                end
                local full_lua_line = "    " .. string.gsub(name, "-", "_")
                -- 如果属性的名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    full_lua_line = "    [\"" .. name .. "\"]"
                -- 如果属性的名称中包含-
                elseif new_prop_format and string.find(name, "-") ~= nil then
                    full_lua_line = "    [\"" .. name .. "\"]"
                end
                -- 属性名字，补齐空格，对齐文字
                if property_name_len < property_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", property_name_max_len - property_name_len)
                end
                full_lua_line = full_lua_line  ..' = {__type__="' .. class_node["property"][name]["type"] .. '" '
                -- 类型名，补齐空格，对齐文字
                if type_name_len < type_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", type_name_max_len - type_name_len)
                end
                if class_node["property"][name]["default"] ~=nil then
                    full_lua_line = full_lua_line .. ',__default__ = "' .. class_node["property"][name]["default"] .. '" '
                    -- 补齐空格，对齐文字
                    if default_len < default_max_len then
                        full_lua_line = full_lua_line .. string.rep(" ", default_max_len - default_len)
                    end
                else
                    -- 没有缺省值，补齐空格，需要增加',__default__ = "" '的长度 16 + 2
                    if default_len < default_max_len then
                        full_lua_line = full_lua_line .. string.rep(" ", default_max_len - default_len + 18)
                    end
                end
                -- 如果不为空，则有GENCODE
                if class_node["property"][name]["functionname"] ~= nil and class_node["property"][name]["setfunction"] ~= nil then
                    full_lua_line = full_lua_line .. ", __gencode__ = {\"" .. class_node["property"][name]["functionname"] .. '('
                    -- 函数体
                    full_lua_line = full_lua_line .. cvt_param_list_for_property(class_node["property"][name]["setfunction"], class_node["property"][name]["origin"])
                    -- 补全
                    full_lua_line = full_lua_line .. ")\"}"
                    -- 如果此属性为只读，且有set函数，则需要添加rwflags
                    if class_node["property"][name]["rwflags"] == "r" then
                        full_lua_line = full_lua_line .. ',rwflags="r"'
                    end
                else
                    -- 如果属性无set函数，而属性为可写，则需要添加rwflags
                    if class_node["property"][name]["rwflags"] == "rw" then
                        full_lua_line = full_lua_line .. ',rwflags="rw"'
                    elseif class_node["property"][name]["rwflags"] == "w" then
                        full_lua_line = full_lua_line .. ',rwflags="w"'
                    end
                end
                if class_node["property"][name]["construct"] == 1 then
                    full_lua_line = full_lua_line .. ',__construct__= 1'
                    print("[WARN] class: " .. class_node["typename"] .. ", property can't set, is construct property [" .. name .. "]")
                else
                    -- 如果有只读选择
                    if class_node["property"][name]["rwflags"] == "r" then
                        print("[WARN] class: " .. class_node["typename"] .. ", property can't set, is read only property [" .. name .. "]")
                    else
                        print("[WARN] class: " .. class_node["typename"] .. ", property can't set, missing set function  [" .. name .. "]")
                    end
                end
                full_lua_line = full_lua_line .. ' },\n'
    
                dest_handle:write(full_lua_line);
            end
        end
        dest_handle:write("  },\n");
    end
    local function write_child_property_code(class_node, dest_handle)
        if class_node["child_property"] ~= nil and type(class_node["child_property"]) == "table" then
            dest_handle:write("  child_property = { \n");
            dest_handle:write("    -- 属性名称  属性类型 缺省值\n");
        
            local type_name_max_len = 1
            -- local default_max_len = 0
            local property_name_max_len = 1
    
            -- 用于排序属性名称
            local sort_name = {}
            -- 查找当前属性列表的类型最长长度
            for name, detail in pairs(class_node["child_property"]) do
                local type_name_len = string.len(detail["type"])
                if type_name_len > type_name_max_len then
                    type_name_max_len = type_name_len + 1
                end
                local property_name_len = string.len(name)
                -- 如果属性的名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    property_name_len = property_name_len + 4;
                -- 如果属性的名称中包含-
                elseif new_prop_format and string.find(name, "-") ~= nil then
                    property_name_len = property_name_len + 4;
                end
                if property_name_len > property_name_max_len then
                    property_name_max_len = property_name_len
                end
                table.insert(sort_name, 1, name)
            end
            -- 排序一下信号名称
            table.sort(sort_name)
    
            -- 信号以字母顺序输出
            for _, name in ipairs(sort_name) do
            --for k, v in pairs(class_node["property"]) do
                local property_name_len = string.len(name)
                -- 如果属性的名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    property_name_len = property_name_len + 4;
                -- 如果属性的名称中包含-
                elseif new_prop_format and string.find(name, "-") ~= nil then
                    property_name_len = property_name_len + 4;
                end
                local full_lua_line = "    " .. string.gsub(name, "-", "_")
                -- 如果属性的名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    full_lua_line = "    [\"" .. name .. "\"]"
                -- 如果属性的名称中包含-
                elseif new_prop_format and string.find(name, "-") ~= nil then
                    full_lua_line = "    [\"" .. name .. "\"]"
                end
                local type_name_len = string.len(class_node["child_property"][name]["type"])
                -- 补齐空格，对齐文字
                if property_name_len < property_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", property_name_max_len - property_name_len)
                end
                full_lua_line = full_lua_line  ..' = {__type__="' .. class_node["child_property"][name]["type"] .. '"'
                -- 补齐空格，对齐文字
                if type_name_len < type_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", type_name_max_len - type_name_len)
                end
                if class_node["child_property"][name]["default"] ~=nil then
                    full_lua_line = full_lua_line .. ',__default__ = "' .. class_node["child_property"][name]["default"] .. '"'
                end
                full_lua_line = full_lua_line .. ' },\n'
    
                dest_handle:write(full_lua_line);
            end
    
            dest_handle:write("  },\n");
        end
    end
    local function write_virtual_method_code(class_node, dest_handle)
        dest_handle:write("  ['virtual-method'] = { \n");
        dest_handle:write("    -- 虚函数名称[- ==> _], 函数返回值, 函数参数列表\n");
    
        if class_node["virtual-method"] ~= nil and type(class_node["virtual-method"]) == "table" then
            local return_name_max_len = 1
            local v_method_name_max_len = 1
    
            -- 用于排序信号名称
            local sort_name = {}
            -- 查找当前属性列表的类型最长长度
            for name, detail in pairs(class_node["virtual-method"]) do
                local return_name_len = string.len(detail["return"])
                if return_name_len > return_name_max_len then
                    return_name_max_len = return_name_len
                end
                local v_method_name_len = string.len(name)
                -- 如果信号名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    v_method_name_len = v_method_name_len + 4
                -- 如果信号名称中包含'-'，则加上4个字符
                elseif string.find(name, '-') then
                    v_method_name_len = v_method_name_len + 4
                end
                if v_method_name_len > v_method_name_max_len then
                    v_method_name_max_len = v_method_name_len
                end
                table.insert(sort_name, 1, name)
            end
            -- 排序一下信号名称
            table.sort(sort_name)
    
            -- 信号以字母顺序输出
            for _, name in ipairs(sort_name) do
                local v_method_name_len = string.len(name)
                local full_lua_line = "    " .. name
                -- 如果信号名称为关键字，则需要加4个字符
                if is_key_name(name) then
                    full_lua_line = "    ['" .. name .. "']"
                    v_method_name_len = v_method_name_len + 4
                -- 如果信号名称中包含'-'，则加上4个字符
                elseif string.find(name, '-') then
                    full_lua_line = "    ['" .. name .. "']"
                    v_method_name_len = v_method_name_len + 4
                end
                -- 补齐空格，对齐文字
                if v_method_name_len < v_method_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", v_method_name_max_len - v_method_name_len)
                end
    
                full_lua_line = full_lua_line ..' = {"' .. class_node["virtual-method"][name]["return"] .. '"'
    
                local return_name_len = string.len(class_node["virtual-method"][name]["return"])
                -- 补齐空格，对齐文字
                if return_name_len < return_name_max_len then
                    full_lua_line = full_lua_line .. string.rep(" ", return_name_max_len - return_name_len)
                end
                full_lua_line = full_lua_line .. ', {' .. cvt_param_type_for_signal(class_node["virtual-method"][name]["parameter"])
                full_lua_line = full_lua_line .. '}, {' .. cvt_param_body_for_signal(class_node["virtual-method"][name]["parameter"]) .. "} }, \n"
                dest_handle:write(full_lua_line);
            end
        end
    
        dest_handle:write("  },\n");
    end
    if type(class_node) ~= "table" then
        print("bad class node!")
    end
    dest_handle:write("---------------------  " .. class_node["typename"] .. "\n");
    -- 输出类的信息全集
    dest_handle:write(gtk_ver .. "." .. class_node["typename"] .. " = {\n");
    -- 给每个类添加一个字段class，用于保存类名
    dest_handle:write("  class = \"" .. class_node["typename"] .. "\", \n");
    if class_node["constructor"] ~= nil then
        write_constructor_code(class_node, dest_handle)
    end
    if class_node["method"] ~= nil then
        --write_method_code(class_node, dest_handle)
    end
    if class_node["virtual-method"] ~= nil then
        -- 可以没有虚函数
        if table_length(class_node["virtual-method"]) > 0 then
            write_virtual_method_code(class_node, dest_handle)
        end
    end
    if class_node["signal"] ~= nil then
        write_signal_code(class_node, dest_handle)
    end
    if class_node["property"] ~= nil then
        write_property_code(class_node, dest_handle)
    end
    -- if class_node["child_property"] ~= nil then
    write_child_property_code(class_node, dest_handle)
    -- end

    if class_node["parent"] ~= nil then
        if gtk_classes[class_node["parent"]] ~=nil then
            dest_handle:write("  parent = " .. gtk_ver .. "." .. gtk_classes[class_node["parent"]]["typename"] .. ",\n");
        else
            print("[ERROR] class: " .. class_node["typename"] .. " 's parent [".. class_node["parent"] .."] is not exist in gtk class list.")
            dest_handle:write("  parent = nil, \n");
        end
    else
        dest_handle:write("  parent = nil, \n");
    end
    if class_node["implement"] ~= nil then
        -- 第一次时，输出{
        local first_tag = "  implement = {"
        local has_out = false;
        for _, name in ipairs(class_node["implement"]) do
            if gtk_interfaces[name] ~=nil then
                dest_handle:write(first_tag .. gtk_ver .. "." .. gtk_interfaces[name]["typename"]);
                -- 后续的都是输出, 
                first_tag = ", "
                has_out = true
            else
                print("[ERROR] class's implement: " .. name .. " is not exist in gtk implement list.")
            end
        end
        if has_out then
            dest_handle:write("}, \n");
        end
    end
    dest_handle:write("};\n\n");
end

function write_gtk_enum_code(enum_name, enum_info, dest_handle)
    dest_handle:write("    " .. enum_info["typename"] .. ' = {\n');
    local enum_sort_name = {}
    local name_len = 0
    local name_max_len = 1
    -- 成员列表不为空
    if enum_info["member"] ~= nil then
        -- 成员名称先取出进行排序
        for key, _ in pairs(enum_info["member"]) do
            table.insert(enum_sort_name, 1, key)
            -- 计算名称
            name_len = string.len(key)
            if name_len > name_max_len then
                name_max_len = name_len
            end
        end
        table.sort(enum_sort_name);
        -- 依序输出
        for _, name in ipairs(enum_sort_name) do
            -- 这两项是必须有的
            name_len = string.len(name)
            local full_lua_line = "        { macro = '" .. enum_info["member"][name]["identifier"] .. "'"
            if name_len < name_max_len then
                full_lua_line = full_lua_line .. string.rep(" ", name_max_len - name_len)
            end
            full_lua_line = full_lua_line .. ', name = "' .. name .. '", '
            if name_len < name_max_len then
                full_lua_line = full_lua_line .. string.rep(" ", name_max_len - name_len)
            end
            -- 如果有nick
            if enum_info["member"][name]["nick"] ~= nil then
                full_lua_line = full_lua_line .. 'nick = "' .. enum_info["member"][name]["nick"] .. '", '
            else
                full_lua_line = full_lua_line .. 'nick = "' .. name .. '", '
            end
            if name_len < name_max_len then
                full_lua_line = full_lua_line .. string.rep(" ", name_max_len - name_len)
            end
            full_lua_line = full_lua_line .. 'value = "' .. enum_info["member"][name]["value"] .. '"}, \n'
            dest_handle:write(full_lua_line);
        end
    end
    dest_handle:write("    },\n");
end

function get_all_class_info(ui_data, root_node, args_child, args_property)
    local function build_enum_info(ui_data, parent_node)
        local enum_info = {}
        -- 简单取出enum节点
        local enum_node = parent_node[1]
        if type(enum_node) ~= "table" then
            return "", nil
        end
        -- must exist name
        local enum_name = get_gtk_ui_property_value_by_name(ui_data, parent_node, "name")
        if enum_name == nil then
            return "", nil
        end
    
        enum_info["name"] = enum_name;
        
        -- c:type
        if enum_node["c:type"] == nil then
            enum_info["typename"] = type_prefix .. enum_name;
        else
            enum_info["typename"] = enum_node["c:type"];
        end
        enum_info["member"] = {}
    
        local child_node = get_gtk_ui_first_child(ui_data, parent_node)
        while child_node ~= nil do
            local node_tag = get_gtk_ui_node_name(ui_data, child_node)
            -- 枚举可能存在重复项
            if node_tag == "member" then
                -- start signal
                local name = get_gtk_ui_property_value_by_name(ui_data, child_node, "name")
                if name ~= nil then
                    local member_info = {}
                    member_info["name"]       = name
                    member_info["value"]      = get_gtk_ui_property_value_by_name(ui_data, child_node, "value") -- v["value"]
                    member_info["nick"]       = get_gtk_ui_property_value_by_name(ui_data, child_node, "glib:nick") -- v["glib:nick"]
                    member_info["identifier"] = get_gtk_ui_property_value_by_name(ui_data, child_node, "c:identifier") -- v["c:identifier"]
                    -- 重复项时，以virtual-method中为准
                    enum_info["member"][name] = member_info
                else
                    print("enumeration: " .. enum_info["name"] .. "have one unnamed member!")
                end
            end
    
            child_node = get_gtk_ui_next_child(ui_data, parent_node, child_node)
        end
    
        return enum_info["name"], enum_info
    end
    local inn_classes = {}
    local inn_interfaces = {}
    local inn_enumerationes = {}
    -- local root_node = get_gtk_ui_root(ns_node)
    local child_node = get_gtk_ui_first_child(ui_data, root_node)
    -- 依次从XML中获取类的信息
    while child_node ~= nil do
        local node_name = get_gtk_ui_node_name(ui_data, child_node)
        if node_name == "class" then
            local class_info, class_name = build_class_info(ui_data, child_node, args_child, args_property)
            if class_info ~= nil then
                inn_classes[class_name] = class_info
            end
        elseif node_name == "interface" then
            local class_info, class_name = build_class_info(ui_data, child_node, args_child, args_property)
            if class_info ~= nil then
                inn_interfaces[class_name] = class_info
            end
        elseif node_name == "enumeration" then
            local enum_name, enum_info = build_enum_info(ui_data, child_node)
            if enum_info ~= nil then
                inn_enumerationes[enum_name] = enum_info
            end
        end
        child_node = get_gtk_ui_next_child(ui_data, root_node, child_node)
    end
    return inn_classes, inn_interfaces, inn_enumerationes
end

function load_gir_handle(xml, gir_file)
    -- 装载XML文件
    local gir_handle = xml.load(gir_file)
    if gir_handle == nil then
        print("open gir file fail!" .. gir_file)
    end
    return gir_handle;
end

function calc_classes_weight(inn_classes)
    -- 删除所有无子结点、父结点的类
    local classes_weight = {}
    for name, detail in pairs(inn_classes) do
        -- 如果已经有一项，则加1，否则，初始为0
        if classes_weight[name] ~= nil then
            classes_weight[name] = classes_weight[name] + 1
        else
            classes_weight[name] = 0
        end
        local parent_name = detail["parent"]
        -- 如果父类不为空，则给父类结点设置一个值
        if inn_classes[parent_name] ~= nil then
            -- 有父类结点，当前结点值至少为1
            classes_weight[name] = classes_weight[name] + 1
            if classes_weight[parent_name] ~= nil then
                classes_weight[parent_name] = classes_weight[parent_name] + 1
            else
                classes_weight[parent_name] = 0
            end
        end
    end
    --[[ 删除不需要的结点
    for name, value in pairs(classes_weight) do
        -- 没有人需要他，删除吧
        if value == 0 then
            print("Not needed class, delete it. [" .. name .. ']')
            inn_classes[name] = nil
        end
    end
    ]]--
    return classes_weight;
end

function calc_classes_level(inn_classes)
    -- 双层循环处理
    local is_finished = true
    repeat
        is_finished = true
        for name, detail in pairs(inn_classes) do
            if detail["level"] == nil then
                local parent_name = detail["parent"]
                if inn_classes[parent_name] == nil then
                    print("class: " .. name .. " hasn't parent");
                    detail["level"] = 1
                else
                    if inn_classes[parent_name]["level"] == nil then
                        is_finished = false
                    else
                        detail["level"] = inn_classes[parent_name]["level"] + 1
                    end             
                end
            end
        end
    until is_finished == true;
end

function write_lua_header(handle, ui_ver, mod_name)
    -- 打开文件，依次写入代码
    handle:write(ui_ver .." = " .. ui_ver .." or {}\n");

    handle:write(ui_ver ..".__version_no__ = \"".. ui_ver.. "\"\n");
    handle:write(ui_ver ..".__module_name__ = \"" .. mod_name .. "\"\n\n");

    handle:write("----  [Gtk interfaces] Start ... \n");
end

function write_all_interfaces(handle, inn_interfaces)
    do
        local sort_name = {}
        -- 取出当前级别的所有名称
        for name, _ in pairs(inn_interfaces) do
            table.insert(sort_name, 1, name)
        end
        -- 排序名称
        table.sort(sort_name);
        -- 根据排序结果输出
        for _, name in ipairs(sort_name) do
            -- write code
            write_gtk_class_code(inn_interfaces[name], handle)
        end
    end
    
    handle:write("----  [Gtk interfaces] End ... \n");
    handle:write("----  [Gtk Classes] Start \n");
end

local function write_all_classes(handle, inn_classes)
    local write_level = 1
    local sort_name = {}
    local is_finished = true
    repeat
        is_finished = true
        sort_name = {}
        -- 取出当前级别的所有名称
        for name, detail in pairs(inn_classes) do
            if detail["level"] == write_level then
                table.insert(sort_name, 1, name)
            elseif detail["level"] > write_level then
                is_finished = false
            end
        end
        -- 排序名称
        table.sort(sort_name);
    
        -- 根据排序结果输出
        for _, name in ipairs(sort_name) do
            -- write code
            write_gtk_class_code(inn_classes[name], handle)
        end
        write_level = write_level + 1
    until is_finished == true;
    -- finish
    handle:write("----  [Gtk Classes] End ... \n"); 
end

local function write_all_enumerates(handle, ui_ver, inn_enumerates)
    -- 依字母顺序输出枚举项
    print("start process gtk enumerates.")
    local enum_sort_name = {}
    for name, _ in pairs(inn_enumerates) do
        table.insert(enum_sort_name, 1, name)
    end
    table.sort(enum_sort_name);
    local gtk_enum_name = ui_ver .. ".GtkEnumerationes"
    -- 根据排序结果输出
    handle:write("----  [Gtk Enumerates] Start ... \n".. gtk_enum_name .. " = ".. gtk_enum_name .. " or {}\n");
    handle:write([[
do
    local merge_list = function (old_list)
        if ]] .. gtk_enum_name .. [[ == nil then
            return old_list
        end
        for i, v in pairs(]].. gtk_enum_name .. [[) do
            old_list[i] = v
        end
        return old_list
    end
    ]] .. gtk_enum_name ..  [[ = merge_list({
    ]]);
    for _, name in ipairs(enum_sort_name) do
        -- write code
        write_gtk_enum_code(name, inn_enumerates[name], handle)
    end
    handle:write("}); end;\n");

    handle:write("----  [Gtk Enumerates] End ... \n");
end

local function write_patch_file(handle, patch_file)
    -- append patch file
    if patch_file ~= nil then
        -- 先打开要写的文件句柄
        local patch_handle = io.open(patch_file, "r")
        if patch_handle ~= nil then
            print("append patch file content.")
            -- 直接读取所有，然后追加到文件后面
            local patch_content = patch_handle:read("a")
            patch_handle:close()
            handle:write(patch_content);
        else
            print("open patch file failed!" .. patch_handle)
        end
    end
end

local gir_file  = arg[1]
local args_file = arg[2]
local lua_file  = arg[3]
local patch_file = arg[4]

-- 扫描剩余参数，并设置相关变量
for i = 4, #arg do -- 允许没有patch_file，因此应该从第4个参数开始扫描
    local param = arg[i]
    if string.find(param, "^%-%-gtk%-ver=") then
        gtk_ver = string.sub(param, 11)
    elseif string.find(param, "^%-%-gtk%-modname=") then
        gtk_mod_name = string.sub(param, 15)
    elseif string.find(param, "^%-%-new%-prop%-format=") then
        -- 判断传入是否为TRUE
        if string.lower(string.sub(param, 19)) == "true" then
            new_prop_format = true
        end
    end
end

-- 简单封装一下
function _check_param_list(gir_file, args_file, lua_file, temp_patch_file)
    if not _check_file_exists(gir_file) then
        print("gir file not exist: " .. gir_file)
        return false
    end
    if not _check_file_exists(args_file) then
        print("args file not exist: " .. args_file)
        return false
    end
    if _check_file_exists(lua_file) then
        print("lua file exist, will overwrite it, " .. lua_file)
    end

    if temp_patch_file ~= nil then
        -- 先打开要写的文件句柄
        if not _check_file_exists(temp_patch_file) then
            print("patch file not exist, will skip it, " .. temp_patch_file)
            patch_file = nil
        end
    end
    return true
end

-- 检查一下参数
if not _check_param_list(gir_file, args_file, lua_file, patch_file) then
    return
end

-- 简单封装一下
function get_widget_property_info(xml, args_file)
    local function read_args_file(xml, args_filename)
        -- args文件需要在外面套一个外壳
        local args_h = io.open(args_filename, "r")
        if args_h == nil then
            print("open args file fail!" .. args_filename)
            return
        end
        -- 读取整个内容
        local content_ = args_h:read("a")
        -- 关闭文件句柄
        io.close(args_h)
        local new_content = string.gsub(content_, "<RANGE>.-</RANGE>", "")
        -- 转换成xml句柄，部分内容不符合XML语法，通过gsub替换
        local args_handle = xml.eval("<gtk>\n" .. new_content .. "\n</gtk>\n")
        if args_handle == nil then
            print("eval args file fail!" .. args_filename)
        end
        return args_handle
    end
    local function build_widget_property_info(args_handle)
        -- 分割字符串
        local function string_split(str, reps)
            local resultStrList = {}
            string.gsub(str,'[^'..reps..']+',function (w)
                table.insert(resultStrList,w)
            end)
            return resultStrList
        end
        local widget_property_list = {}
        local child_property_list = {}
        -- ARG结点
        local root_node = get_gtk_ui_root(args_handle);
        local parent_node = get_gtk_ui_first_child(args_handle, root_node)
        -- 首层结点
        while parent_node ~= nil do
            -- 第二层结点
            local child_node = get_gtk_ui_first_child(args_handle, parent_node)
            local prop_item = {}
            local widget_name = nil
            local is_child_prp = false
    
            while child_node ~= nil do
                local node_name = get_gtk_ui_node_name(args_handle, child_node)
                local node_value = get_gtk_ui_node_value(args_handle, child_node)
                if node_name == "NAME" then
                    if node_value ~= nil then
                        -- need trip some characters.
                        local data = string_split(node_value, "::");
                        widget_name = data[1];
                        -- 属性名称
                        prop_item["origin"] = data[2];
                    end
                elseif node_name == "FLAGS" then
                    prop_item["flags"] = node_value;
                    if node_value ~= nil and string.find(node_value, 'c', 1, true) then
                        -- 是否为子属性
                        is_child_prp = true
                    end
                    -- 标志字段仅保留r/rw，删除csX
                    prop_item["flags"] = string.gsub(prop_item["flags"], "[^rw]", "");
                elseif node_name == "DEFAULT" then
                    if node_value ~= nil then
                        -- 属性缺省值
                        prop_item["default"] = node_value
                    end
                elseif node_name == "TYPE" then
                    if node_value ~= nil then
                        prop_item["type"] = node_value
                    end
                end
                child_node = get_gtk_ui_next_child(args_handle, parent_node, child_node)
            end
            if widget_name and prop_item["origin"] then
                if is_child_prp then
                    if child_property_list[widget_name] == nil then
                        child_property_list[widget_name] = {}
                    end
                    if child_property_list[widget_name][prop_item["origin"]] ~= nil then
                        print("[DUP] ".. widget_name .. "::" .. prop_item["origin"] .. " is not nil")
                    else
                        child_property_list[widget_name][prop_item["origin"]] = prop_item
                    end
                else
                    if widget_property_list[widget_name] == nil then
                        widget_property_list[widget_name] = {}
                    end
                    if widget_property_list[widget_name][prop_item["origin"]] ~= nil then
                        print("[DUP] ".. widget_name .. "::" .. prop_item["origin"] .. " is not nil")
                    else
                        widget_property_list[widget_name][prop_item["origin"]] = prop_item
                    end
                end
            end
    
            parent_node = get_gtk_ui_next_child(args_handle, root_node, parent_node)
        end
        return child_property_list, widget_property_list
    end
    
    -- 装载args文件
    local args_handle = read_args_file(xml, args_file);
    -- 从args文件中获取类的子属性
    local child_property_list, property_list = build_widget_property_info(args_handle);
    -- 此时，不再需要args_handle的数据了
    args_handle = nil;

    return child_property_list, property_list;
end

-- 获取类的子属性和属性信息
local gtk_args_child_property_list, gtk_args_property_list = get_widget_property_info(xml_obj, args_file);

-- 装载XML文件
local gir_handle = load_gir_handle(xml_obj, gir_file);
if gir_handle == nil then
    return
end

-- 获取ns结点
local ns_node = get_namespace_node(gir_handle)
if ns_node == nil then
    print("gir file missing namespace node!")
    return
end

-- 从namespace节点中修改相应的特殊前缀
if get_gtk_ui_property_value_by_name(gir_handle, ns_node, "c:symbol-prefixes") ~= nil then
    func_prefix = get_gtk_ui_property_value_by_name(gir_handle, ns_node, "c:symbol-prefixes")
end
if get_gtk_ui_property_value_by_name(gir_handle, ns_node, "c:identifier-prefixes") ~= nil then
    type_prefix = get_gtk_ui_property_value_by_name(gir_handle, ns_node, "c:identifier-prefixes")
end

-- 依次从XML中获取类的信息
gtk_classes, gtk_interfaces, gtk_enumerationes = get_all_class_info(gir_handle, ns_node, gtk_args_child_property_list, gtk_args_property_list)

function patch_classes_item_typeinfo(inn_classes, inn_interfaces, inn_enums)
    local function get_match_type(short_name, classes)
        local full_name = type_prefix .. short_name
        if classes[short_name] ~= nil and classes[short_name]["typename"] == full_name then
            return full_name
        end
    end
    local function need_patch_name(name)
        -- 判断参数首、末字母，确定是否需要进行patch修改
        if string.byte(name, 1) == 123 and -- { }
            string.byte(name, string.len(name)) == 125 then
            return true
        end
        return false
    end
    local function patch_classes_typeinfo(c_name, s_name, param_list, type_name,  classes, interfaces, enums)
        -- 判断一下信号的参数信息
        for _, one_param in ipairs(param_list) do
            -- 判断参数类型
            if one_param[1] ~= nil and 
               type(one_param[1]) == "string" then
                -- 判断参数首、末字母，确定是否需要进行patch修改
                if need_patch_name(one_param[1]) then
                    -- print("[WARN] class " .. c_name .. "'s ".. type_name .. " " .. s_name .. " need patch param [".. one_param[1] .. "," .. one_param[2] .. "]!")
                    -- 首先从classes里查找
                    local real_name = string.sub(one_param[1], 2, string.len(one_param[1]) - 1)
                    local full_name = get_match_type(real_name, classes)
                    if full_name == nil then
                        -- 然后从interfaces中查找
                        full_name = get_match_type(real_name, interfaces)
                        if full_name == nil then
                            -- 最后从枚举中查找
                            full_name = get_match_type(real_name, enums)
                            -- 匹配到
                            if full_name ~= nil then
                                -- 枚举中查找到，就不应该带指针标识
                                one_param[1] = full_name;
                            else
                                print("[ERROR] class " .. c_name .. "'s ".. type_name .. " " .. s_name .. " need patch param[".. real_name .. "," .. one_param[2] .. "]!!")
                            end
                        else
                            one_param[1] = full_name .. "*";
                        end
                    else
                        one_param[1] = full_name .. "*";
                    end
                end
            end
        end
    end
    local function patch_classes_signal_typeinfo(c_name, s_name, one_signal, classes, interfaces, enums)
        if one_signal["parameter"] == nil then
            return;
        end
        patch_classes_typeinfo(c_name, s_name, one_signal["parameter"], "signal", classes, interfaces, enums);
    end
    local function patch_classes_method_typeinfo(c_name, s_name, one_method, classes, interfaces, enums)
        if one_method["parameter"] == nil then
            return;
        end
        patch_classes_typeinfo(c_name, s_name, one_method["parameter"], "method", classes, interfaces, enums);
    end
    local function patch_classes_v_method_typeinfo(c_name, s_name, one_method, classes, interfaces, enums)
        if one_method["parameter"] == nil then
            return;
        end
        patch_classes_typeinfo(c_name, s_name, one_method["parameter"], "virtual-method", classes, interfaces, enums);
    end
    local function patch_classes_constructor_typeinfo(c_name, s_name, one_construct, classes, interfaces, enums)
        if one_construct["parameter"] == nil then
            return;
        end
        patch_classes_typeinfo(c_name, s_name, one_construct["parameter"], "constructor", classes, interfaces, enums);
    end
    local function patch_classes_property_typeinfo(c_name, p_name, one_property, classes, interfaces, enums)
        if one_property["setfunction"] == nil or one_property["setfunction"]["parameter"] == nil then
            return;
        end
        patch_classes_typeinfo(c_name, p_name, one_property["setfunction"]["parameter"], "property", classes, interfaces, enums);
    end

    -- 遍历所有的接口类
    for class_name, class_detail in pairs(inn_interfaces) do
        --if class_name == "PrintOperationPreview" then
        --    debug.debug()
        --end
        -- 处理信号
        for signal_name, signal_detail in pairs(class_detail["signal"]) do
            patch_classes_signal_typeinfo(class_name, signal_name, signal_detail, inn_classes, inn_interfaces, inn_enums);
        end
        -- 处理函数
        for method_name, method_detail in pairs(class_detail["method"]) do
            patch_classes_method_typeinfo(class_name, method_name, method_detail, inn_classes, inn_interfaces, inn_enums);
        end
        -- 处理虚函数
        for vmethod_name, vmethod_detail in pairs(class_detail["virtual-method"]) do
            patch_classes_v_method_typeinfo(class_name, vmethod_name, vmethod_detail, inn_classes, inn_interfaces, inn_enums);
        end
        -- 处理构造函数
        -- 处理属性
        for prop_name, prop_detail in pairs(class_detail["property"]) do
            patch_classes_property_typeinfo(class_name, prop_name, prop_detail, inn_classes, inn_interfaces, inn_enums);
        end
    end

    -- 遍历所有的类
    for class_name, class_detail in pairs(inn_classes) do
        -- 处理信号
        for signal_name, signal_detail in pairs(class_detail["signal"]) do
            patch_classes_signal_typeinfo(class_name, signal_name, signal_detail, inn_classes, inn_interfaces, inn_enums);
        end
        -- 处理函数
        for method_name, method_detail in pairs(class_detail["method"]) do
            patch_classes_method_typeinfo(class_name, method_name, method_detail, inn_classes, inn_interfaces, inn_enums);
        end
        -- 处理虚函数
        for vmethod_name, vmethod_detail in pairs(class_detail["virtual-method"]) do
            patch_classes_v_method_typeinfo(class_name, vmethod_name, vmethod_detail, inn_classes, inn_interfaces, inn_enums);
        end
        -- 处理构造函数
        for constructor_name, constructor_detail in pairs(class_detail["constructor"]) do
            patch_classes_constructor_typeinfo(class_name, constructor_name, constructor_detail, inn_classes, inn_interfaces, inn_enums);
        end
        -- 处理属性
        for prop_name, prop_detail in pairs(class_detail["property"]) do
            patch_classes_property_typeinfo(class_name, prop_name, prop_detail, inn_classes, inn_interfaces, inn_enums);
        end
    end
end

-- 重新处理一下各个函数、信号、虚函数、属性的未被正确解析的类型信息
patch_classes_item_typeinfo(gtk_classes, gtk_interfaces, gtk_enumerationes);

-- 删除所有无子结点、父结点的类
--local check_classes = calc_classes_weight(gtk_classes);

-- 为每一个类赋值一个级别，后续按照level级别来生成代码
if gtk_classes["Object"] ~= nil then
    gtk_classes["Object"]["level"] = 1
end

-- 先打开要写的文件句柄
local lua_handle = io.open(lua_file, "w")
if lua_handle == nil then
    print("open file to write, failed!" .. lua_file)
    return
end

-- 双层循环处理
calc_classes_level(gtk_classes);

-- 打开文件，依次写入代码
write_lua_header(lua_handle, gtk_ver, gtk_mod_name);

write_all_interfaces(lua_handle, gtk_interfaces);

write_all_classes(lua_handle, gtk_classes);

-- 依字母顺序输出枚举项
write_all_enumerates(lua_handle, gtk_ver, gtk_enumerationes);

print("finish process gtk enumerates.")

-- append patch file
write_patch_file(lua_handle, patch_file);

lua_handle:close();
print("convert finished!")
